﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.IO;

namespace GestureSaver
{
    public partial class MainWindow : Window
    {
        Gesture gesture;
        private KinectSensor sensor;
        private WriteableBitmap _ColorImageBitmap;
        private Skeleton[] skeletonData = new Skeleton[6];
        private IEnumerable<Skeleton> trackedSkeletons;
        private bool capturing;
        System.Windows.Forms.Timer timer;
        private int CapturingWaitTime = 3; // 3 seconds to start capturing.
        private DateTime CapturingStartTime;
        private string DBFILE = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+@"\DB\";
     
        public MainWindow()
        {
            InitializeComponent();
        }
        
        private void Grid_Loaded(object sender, RoutedEventArgs e)
        {
            cmbGestureTypes.ItemsSource = Enum.GetValues(typeof(GestureType));
            cmbGestureTypes.SelectedIndex = 0;

            KinectSensor sensor = KinectSensor.KinectSensors.FirstOrDefault();
            InitializeKinect(sensor);
        }

        private void InitializeKinect(KinectSensor sensor)
        {
            if (sensor != null)
            {
                this.sensor = sensor;

                sensor.ColorStream.Enable();
                sensor.SkeletonStream.Enable();
                
                this._ColorImageBitmap = new WriteableBitmap(sensor.ColorStream.FrameWidth, sensor.ColorStream.FrameHeight, 96, 96, PixelFormats.Bgr32, null);
                imgVideo.Source = this._ColorImageBitmap;
                
                sensor.ColorFrameReady += Kinect_ColorFrameReady;
                sensor.DepthFrameReady += Kinect_DepthFrameReady;
                sensor.SkeletonFrameReady += Kinect_SkeletonFrameReady;
                sensor.Start();
            }
        }

        void Kinect_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (DepthImageFrame frame = e.OpenDepthImageFrame())
            {
                if (frame != null)
                {
                    short[] pixelData = new short[frame.PixelDataLength];
                    frame.CopyPixelDataTo(pixelData);
                    imgVideo.Source = BitmapImage.Create(frame.Width, frame.Height, 96, 96, PixelFormats.Gray16, null, pixelData, frame.Width * frame.BytesPerPixel);
                }
            }
        }

        void Kinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            using(SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            {
                if (skeletonFrame != null)
                {
                    skeletonFrame.CopySkeletonDataTo(skeletonData);

                    trackedSkeletons = skeletonData.Where(s => s.TrackingState == SkeletonTrackingState.Tracked);

                    Skeleton trackedSkeleton = trackedSkeletons.FirstOrDefault();

                    if (trackedSkeleton != null)
                    {
                        SkeletonDrawer.DrawSkeleton(trackedSkeleton, Brushes.Green, canvas, sensor);

                        if (capturing)
                        {
                            gesture.AddFrame(trackedSkeleton.Joints, DateTime.Now);
                        }
                    }
                }
            }
        }

        private void Kinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame frame = e.OpenColorImageFrame())
            {
                if (frame != null)
                {
                    byte[] pixelData = new byte[frame.PixelDataLength];
                    frame.CopyPixelDataTo(pixelData);
                    imgVideo.Source = BitmapImage.Create(frame.Width, frame.Height, 96, 96, PixelFormats.Bgr32, null, pixelData, frame.Width * frame.BytesPerPixel);
                }
            }
        }

        private void btnDepth_Click(object sender, RoutedEventArgs e)
        {
            if (!sensor.DepthStream.IsEnabled)
            {
                sensor.DepthStream.Enable();
                sensor.ColorStream.Disable();
            }
        }

        private void btnColor_Click(object sender, RoutedEventArgs e)
        {
            if (!sensor.ColorStream.IsEnabled)
            {
                sensor.ColorStream.Enable();
                sensor.DepthStream.Disable();
            }
        }

        private void SaveToFile(UIElement source, string fileName)
        {
            double w = source.RenderSize.Width;
            double h = source.RenderSize.Height;

            RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)w, (int)h, 96, 96, PixelFormats.Pbgra32);
            VisualBrush sourceBrush = new VisualBrush(source);

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            using (drawingContext)
            {
                drawingContext.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0), new System.Windows.Point(w, h)));
            }
            renderTarget.Render(drawingVisual);

            PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
            pngEncoder.Frames.Add(BitmapFrame.Create(renderTarget));

            pngEncoder.Save(new FileStream(fileName, FileMode.Create));
        }

        private void btnSnapshot_Click(object sender, RoutedEventArgs e)
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+@"\";
            string fileName = "Snapshot_";

            int id = 1;
            while (File.Exists(path + fileName + id + ".png"))
            {
                id++;
            }

            SaveToFile(gridSnapshot, path + fileName + id + ".png");
        }

        private void btnCapture_Click(object sender, RoutedEventArgs e)
        {
            if (!capturing) 
            {
                timer = new System.Windows.Forms.Timer();
                timer.Interval = 50;
                timer.Tick += timer_Tick;
                CapturingStartTime = DateTime.Now.AddSeconds(CapturingWaitTime);
                timer.Start();
                btnCapture.IsEnabled = false;
            }
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            StopCapture();
            timer.Stop();
            lblInfo.Text = "Ready";
            gridInfo.Background = Brushes.White;
            btnCapture.IsEnabled = true;
        }

        void timer_Tick(object sender, EventArgs e)
        {
            if (DateTime.Now < CapturingStartTime)  
            {
                lblInfo.Text = "Wait " + ((CapturingStartTime - DateTime.Now).Seconds + 1) + " seconds";
            }
            else
            {
                timer.Stop();
                lblInfo.Text = "Recording gesture ...";
                gridInfo.Background = Brushes.Blue;
                StartCapture();
            }
        }

        private void StopCapture()
        {
            capturing = false;

            if (gesture != null && gesture.data.Count > 0)
            {
                int id = -1;
                string fileName = " ";

                string dir = DBFILE + gesture.gestureType.ToString();
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }

                do
                {
                    id++;
                    fileName = ConstructFileName(gesture.gestureType.ToString(), id);
                }
                while (File.Exists(fileName));

                gesture.SaveToFile(fileName);
            }
        }

        private void StartCapture()
        {
            capturing = true;
            gesture = new Gesture() { gestureType = (GestureType)cmbGestureTypes.SelectedValue };
        }

        private string ConstructFileName(string gestureName, int id)
        {
            return DBFILE + gestureName + @"\" + gestureName + "_" + id.ToString("D3") + ".txt";
        }

        private void btnTiltUp_Click(object sender, RoutedEventArgs e)
        {
            if (sensor.ElevationAngle + 2 < sensor.MaxElevationAngle)
            {
                sensor.ElevationAngle += 2;
                txtTiltAngle.Text = "Tilt Angle: " + sensor.ElevationAngle.ToString();
            }
        }

        private void btnTiltDown_Click(object sender, RoutedEventArgs e)
        {
            if (sensor.ElevationAngle - 2 > sensor.MinElevationAngle)
            {
                sensor.ElevationAngle -= 2;

                txtTiltAngle.Text = "Tilt Angle: " + sensor.ElevationAngle.ToString();
            }
        }

    }
}
